package com.fast.develop.dm.configuration;

import com.fast.develop.dm.configuration.annotation.EnableDomain;
import com.fast.develop.dm.configuration.properties.DomainModelPropesties;
import com.fast.develop.dm.core.ModuleContextFactory;
import com.fast.develop.dm.core.plugin.PluginRegister;
import com.fast.develop.dm.core.registry.ModuleRegistry;
import com.fast.develop.dm.integration.HibernateModuleConfiguration;
import com.fast.develop.dm.integration.HibernateModuleConfigurationBuilder;
import com.fast.develop.dm.integration.context.DefaultDomainModuleContextFactory;
import com.fast.develop.dm.plugin.table.exporter.PluginTableExporterRegister;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ImportAware;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;

import javax.sql.DataSource;
import java.util.*;


/**
 * @author 莫寅
 * 领域模型自动装配
 */
@EnableConfigurationProperties(DomainModelPropesties.class)
public class DomainAutoConfiguration implements ImportAware {


    @Autowired
    private DataSource dataSource;

    @Autowired
    private DomainModelPropesties domainModelPropesties;

    @Autowired
    protected RequestMappingHandlerMapping requestMappingHandlerMapping;

    private Map annotationProperties;

    @Autowired
    private ApplicationContext applicationContext;

    /**
     * 请求拦截器
     */
    private final ObjectProvider<List<PluginRegister>> luginRegisterProvider;

    public DomainAutoConfiguration(ObjectProvider<List<PluginRegister>> luginRegisterProvider) {
        this.luginRegisterProvider = luginRegisterProvider;
    }

    public ModuleRegistry getModuleRegistry(){
        ModuleRegistry moduleRegistry = new ModuleRegistry();
        List<PluginRegister> registers = luginRegisterProvider.getIfAvailable(Collections::emptyList);
        registers.forEach(register -> {
            moduleRegistry.register(register);
        });
        return moduleRegistry;
    }

    @Bean
    public ModuleContextFactory moduleContextFactory(){

        Map properties = new HashMap();
        properties.put("hibernate.show_sql", domainModelPropesties.isShowSql());
        if(domainModelPropesties.getDdlAuto() != null){
            properties.put("hibernate.hbm2ddl.auto", domainModelPropesties.getDdlAuto().getValue());
        }

        HibernateModuleConfiguration hibernateModuleConfiguration = new HibernateModuleConfigurationBuilder()
                .dataSource(dataSource)
                .mappingResources(getMappingResources())
                .packagesToScan(getPackagesToScan())
                .annotatedClasses(getAnnotatedClasses())
                .properties(properties)
                .enableResourcesRest()
                .build();

        ModuleContextFactory moduleContextFactory = new DefaultDomainModuleContextFactory(applicationContext, getModuleRegistry(), requestMappingHandlerMapping);
        moduleContextFactory.create(hibernateModuleConfiguration);
        return moduleContextFactory;
    }



    private String[] getPackagesToScan(){
        LinkedList packagesToScan = ((LinkedList)annotationProperties.get("packagesToScan"));
        if(((String[])packagesToScan.get(0)).length != 0){
            return (String[]) packagesToScan.get(0);
        }else{
            return domainModelPropesties.getPackagesToScan();
        }
    }


    private Class[] getAnnotatedClasses(){
        LinkedList annotatedClasses = ((LinkedList)annotationProperties.get("annotatedClasses"));
        if(((Class[])annotatedClasses.get(0)).length != 0){
            return (Class[]) annotatedClasses.get(0);
        }else{
            return domainModelPropesties.getAnnotatedClasses();
        }
    }

    private String[] getMappingResources(){
        LinkedList mappingResources = ((LinkedList)annotationProperties.get("mappingResources"));
        if(((String[])mappingResources.get(0)).length != 0){
            return (String[]) mappingResources.get(0);
        }else{
            return domainModelPropesties.getMappingResources();
        }
    }

    @Override
    public void setImportMetadata(AnnotationMetadata importMetadata) {
        annotationProperties = importMetadata.getAllAnnotationAttributes(EnableDomain.class.getName());
    }
}
